'''
Created on May 1, 2012

@author: KafKef
'''

import os
import time
import thread
import sqlite3 as lite


from dexen.system.client import CLIENT_DB
from dexen.system.common.states import JobState

#===============================================================================
#  Value Objects
#===============================================================================
class JobInfo(object):
    def __init__(self, job_state):
        assert isinstance(job_state, JobState)
        self.id = job_state.get_id()
        self.name = job_state.get_name()
        self.start_time = job_state.get_start_time()
        self.status = job_state.get_status()
        self.scores = job_state.get_scores()
        self.job_state = job_state
        self.svr_info = None

    def get_svr_info(self):
        return self.svr_info
    
    def set_svr_info(self, svr_info):
        self.svr_info = svr_info
    
    def get_job_state(self):
        return self.job_state
    
    def get_id(self):
        return self.id
    
    def get_name(self):
        return self.name
    
    def get_start_time(self):
        return self.start_time
    
    def get_start_time_str(self):
        return time.strftime("%Y/%m/%d-%H:%M", time.localtime(self.start_time))
    
    def get_scores(self):
        return self.scores
    
    def is_running(self):
        return self.job_state.is_running()
    
    def get_status(self):
        return self.status
    
    def set_status(self, status):
        self.status = status
    
    def __hash__(self):
        svr_info = self.svr_info
        assert isinstance(svr_info, ServerInfo)
        svr_name = svr_info.get_name()
        svr_start_time = svr_info.get_start_time()
        return hash((self.id, svr_name, svr_start_time))
    
    def __eq__(self, other):
        assert isinstance(other, JobInfo)
        return self.get_id() == other.get_id() and self.svr_info == other.get_svr_info()
    
    
    
class ServerInfo(object):
    def __init__(self, row=None):
        if row == None: return
        assert isinstance(row, lite.Row)
        self.set_info(row["IpAddress"], row["StartTime"])

    def set_info(self, name, start_time, is_connected=False):
        self.name = name
        self.start_time = start_time
        self.jobs = {} # job_id: JobInfo
        if is_connected:
            self.status = "Connected"
        else:
            self.status = "Disconnected"
    
    def get_status(self):
        return self.status
    
    def is_connected(self):
        return self.status != "Disconnected"
    
    def connect(self):
        self.status = "Connected"
        
    def disconnect(self):
        self.status = "Disconnected"
        for job_info in self.jobs.values():
            assert isinstance(job_info, JobInfo)
            job_info.set_status("Disconnected")

    def get_name(self):
        return self.name
    
    def get_start_time(self):
        return self.start_time
    
    def get_start_time_str(self):
        return time.strftime("%Y/%m/%d-%H:%M", time.localtime(self.start_time)) 

    def get_jobs(self):
        return self.jobs.values()

    def get_job_info(self, job_id):
        assert self.jobs.has_key(job_id)
        return self.jobs[job_id]

    def add_job(self, job_info):
        assert isinstance(job_info, JobInfo)
        self.jobs[job_info.get_id()] = job_info
        job_info.set_svr_info(self)
    
    def clear_jobs(self):
        self.jobs.clear()
    
    def __hash__(self):
        return hash((self.name, self.start_time))

    def __eq__(self, other):
        return self.name == other.name and self.start_time == other.start_time
    


#===============================================================================
# DB Schema Definition
#===============================================================================

print "Client db: ", CLIENT_DB

client_schema = """

CREATE TABLE IF NOT EXISTS
Server(
    Id INTEGER PRIMARY KEY,
    Name TEXT,
    StartTime REAL,
    IpAddress TEXT,
    UNIQUE(IpAddress, StartTime)
);

CREATE TABLE IF NOT EXISTS
Job( 
    Id INTEGER,
    JobState BLOB,
    SvrId INTEGER,
    FOREIGN KEY(SvrId) REFERENCES Server(Id) ON DELETE CASCADE,
    PRIMARY KEY(Id, SvrId)
);

CREATE TABLE IF NOT EXISTS 
Action(
    Id INTEGER,
    Object BLOB,
    JobId INTEGER,
    SvrId INTEGER,
    FOREIGN KEY(JobId, SvrId) REFERENCES Job(Id, SvrId) ON DELETE CASCADE,
    PRIMARY KEY(Id, JobId, SvrId)
);

CREATE TABLE IF NOT EXISTS 
Archive(
    IndId INTEGER,
    Name TEXT,
    Content BLOB,
    JobId INTEGER,
    SvrId INTEGER,
    FOREIGN KEY(JobId, SvrId) REFERENCES Job(Id, SvrId) ON DELETE CASCADE
);

"""

connections = {}

# Ensures to return a different connection object per thread.
def get_connection():
    global connections
    tid = thread.get_ident()
    if not connections.has_key(tid):
        connections[tid] = lite.connect(CLIENT_DB)
    assert isinstance(connections[tid], lite.Connection)
    connections[tid].row_factory = lite.Row
    return connections[tid]

def clear():
    global connections
    for conn in connections.values():
        conn.close()
    connections.clear()
    # Remove the client DB
    if os.path.exists(CLIENT_DB):
        os.remove(CLIENT_DB)

def initialize():
    conn = lite.connect(CLIENT_DB)
    assert isinstance(conn, lite.Connection)
    c = conn.cursor()
    assert isinstance(c, lite.Cursor)
    c.executescript(client_schema)
    conn.commit()
    c.close()
    conn.close()
    
#===============================================================================
# Main for testing
#===============================================================================
def main():
    initialize()

if __name__ == "__main__":
    main()